#ifndef __MY_BLOCKING_PRIORITY_QUEUE_H__
#define __MY_BLOCKING_PRIORITY_QUEUE_H__

#include "noncopy.h"

#include <memory>
#include <queue>
#include <mutex>
#include <condition_variable>

template<class T>
class BlockingPriorityQueue : public NonCopyable {
private:
	using val_t = T;
	using val_sp = std::shared_ptr<val_t>;

private:
	mutable std::mutex mutex_;
	std::condition_variable condvar_;
	std::priority_queue<val_sp> queue_;

public:
	bool put(val_sp item) {
		{
			std::lock_guard<std::mutex> lock(mutex_);
			queue_.push(item);
		}
		condvar_.notify_all();
		return true;
	}

	void pop() {
		std::lock_guard<std::mutex> lock(mutex_);
		queue_.pop();
	}

	val_sp take(bool rm) {
		std::unique_lock<std::mutex> lock(mutex_);
		condvar_.wait(lock, [this] { return !queue_.empty(); });
		auto front = queue_.top();
		if (rm) queue_.pop();
		return front;
	}

	int size() const {
		std::lock_guard<std::mutex> lock(mutex_);
		return queue_.size();
	}

	bool empty() const {
		std::lock_guard<std::mutex> lock(mutex_);
		return queue_.empty();
	}

	bool interrupt_take() {
		condvar_.notify_all();
		return true;
	}
};

#endif // __MY_BLOCKING_PRIORITY_QUEUE_H__
